﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using Newtonsoft.Json;
using T.ServiceComponent.Database.Service;
using T.FAS.Runtime.DataModel.Dao;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.Error;
using T.FAS.Runtime.Base.Entity;

namespace T.FAS.Runtime.DataModel.Dao
{
    public class DataObjectLogic
    {
        public virtual string MetaDataID => "DataObject";
        public virtual string MetaDataName => "数据对象";

        public DataObjectELBDao DataObjectDao => new DataObjectELBDao();
        public DataColumnELBDao DataColumnELBDao => new DataColumnELBDao();
        private readonly DataObjectRelationELBDao _dataObjectRelationELBDao = new DataObjectRelationELBDao();
        private readonly DataObjectIndexELBDao _dataObjectIndexELBDao = new DataObjectIndexELBDao();
        private readonly DataObjectIndexColumnELBDao _dataObjectIndexColumnELBDao = new DataObjectIndexColumnELBDao();
        private readonly DatabaseLogic _databaseLogic = new DatabaseLogic();
        private readonly StaticDataObjectPresetDataELBDao _staticDataObjectPresetDataELBDao = new StaticDataObjectPresetDataELBDao();
        private readonly DataColumnCategoryInfoELBDao _dataColumnCategoryInfoELBDao= new DataColumnCategoryInfoELBDao();
        private readonly DataObjectColumnHelpSettingELBDao _dataObjectColumnHelpSettingELBDao = new DataObjectColumnHelpSettingELBDao();
        
        public DataObjectLogic()
        {
        }

        /// <summary>
        /// 初始化DO内容
        /// </summary>
        /// <param name="do"></param>
        public virtual void InitializeDO(DataObject @do)
        {
            if (@do == null)
                return;
            var unifyCode = $"元数据类型{DataModelConst.DOMetaType}的元数据Code:{@do.Code},ID:{@do.ID}";
            if (@do.Database == null)
            {
                @do.Database = _databaseLogic.GetDatabaseByID(@do.DatabaseID);
                if (@do.Database == null)
                {
                    throw new FasException(DataModelErrorCode.DO.InitError, $"{unifyCode}的DB:{@do.DatabaseID}不存在");
                }
            }
        }

        #region 获取元数据内容
        /// <summary>
        /// 通过ID获取DO信息
        /// </summary>
        /// <param name="dataObjectID"></param>
        /// <returns></returns>
        public virtual DataObject GetDataObjectByID(string dataObjectID)
        {
            var @do = DataObjectDao.GetDataObjectByID(dataObjectID);
            InitializeDO(@do);
            return @do;
        }

        /// <summary>
        /// 通过Code获取DO实例
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public virtual DataObject GetDataObjectByCode(string code)
        {
            var @do = DataObjectDao.GetDataObjectByCode(code);
            InitializeDO(@do);
            return @do;
        }

        /// <summary>
        /// 根据列ID获取列元数据
        /// </summary>
        /// <param name="dataColumnID"></param>
        /// <returns></returns>
        public DataColumn GetDataColumn(string dataColumnID)
        {
            var dataColumnELBDao = new DataColumnELBDao();
            return dataColumnELBDao.GetDataColumn(dataColumnID);
        }

        public virtual List<DataObjectIndex> GetDataObjectIndexsByDataObjectID(Dictionary<string, string> filter)
        {
            return DataObjectDao.GetDataObjectIndexsByDataObjectID(filter);
        }

        public virtual List<DataObject> GetDataObjects(Dictionary<string, string> filter)
        {
            var DOs = DataObjectDao.GetDataObjects(filter);
            DOs.ForEach(o => InitializeDO(o));
            return DOs;
        }
        #endregion

        #region 新增
        /// <summary>
        /// 保存DataObject
        /// </summary>
        /// <param name="dataObject"></param>
        public virtual void SaveDataObject(DataObject dataObject)
        {
            var unifyCode = $"元数据类型{DataModelConst.DOMetaType}的元数据Code:{dataObject?.Code},ID:{dataObject?.ID}";
            dataObject.LogicTableName = dataObject.LogicTableName?.Trim();  //默认Trim掉，防止生成DDL出错
            //处理Columns，给系统默认字段赋值
            if (dataObject.Columns != null && dataObject.Columns.Count > 0)
            {
                dataObject.Columns.ForEach(col =>
                {
                    //col.ID = Guid.NewGuid().ToString(); //不向Column赋值主键id，前端生成，保证修改时ID不变
                    col.DataObjectID = dataObject.ID; //向Column赋值外键id
                    col.ColumnName = col.ColumnName.Trim(); //列名默认Trim掉，防止生成DDL出错
                    EntityTools.FillSystemFiledForAdd(col, dataObject);
                });
            }
            //处理Relation，给系统默认字段赋值
            if (dataObject.DataObjectRelations != null && dataObject.DataObjectRelations.Count > 0)
            {
                foreach (var re in dataObject.DataObjectRelations)
                {
                    if (string.IsNullOrEmpty(re.FromDoID.Trim()))
                    {
                        throw new FasException(DataModelErrorCode.DO.CreateError, $"{unifyCode}的关联关系:{re.ID}的FromDoID 外键关联的数据对象ID不能为空！");
                    }
                    /*
                     * 兼容元数据导入导出逻辑，导入导出逻辑不能依赖DO导入顺序：
                        导入导出时：re.FromColumnID不会为空
                        新增时：re.FromColumnID为空，需要关联取出DO数据后赋值
                        FromColumnID：DoR中父级DO的主键列ID，关键字段需要后端获取
                     */
                    if (string.IsNullOrEmpty(re.FromColumnID))
                    {
                        //判断是否自关联
                        if (string.Equals(re.FromDoID, dataObject.ID))
                        {
                            re.FromColumnID = dataObject.Columns.Where(o => o.IsPkColumn).FirstOrDefault()?.ID;
                        }
                        else
                        {
                            var FKDO = DataObjectDao.GetDataObjectByID(re.FromDoID);
                            if (FKDO == null)
                            {
                                throw new FasException(DataModelErrorCode.DO.CreateError, $"{unifyCode}的外键关联的数据对象 id:{re.FromDoID}不存在！");
                            }
                            re.FromColumnID = FKDO.Columns.Where(o => o.IsPkColumn).FirstOrDefault()?.ID; //获取引用DO的主键列标识(ID列)
                        }
                        if (string.IsNullOrEmpty(re.FromColumnID))
                            throw new FasException(DataModelErrorCode.DO.CreateError, $"{unifyCode}未获取到外键关联:{re.ID}的数据对象：{re.FromColumnID}的主键列信息！");
                    }
                    re.ToDoID = dataObject.ID; //向DOR中添加ToDoID外键
                    EntityTools.FillSystemFiledForAdd(re, dataObject);
                };
            }
            //处理Index，给系统默认字段赋值
            if (dataObject.DataObjectIndexs != null && dataObject.DataObjectIndexs.Count > 0)
            {
                dataObject.DataObjectIndexs.ForEach(ind =>
                {
                    EntityTools.FillSystemFiledForAdd(ind, dataObject);
                    //ind.ID = Guid.NewGuid().ToString(); //向Index赋值主键id，前端生成
                    ind.DataObjectID = dataObject.ID; //向index赋值外键id
                    if (ind.Columns != null)
                    {
                        ind.Columns.ForEach(indCol =>
                        {
                            EntityTools.FillSystemFiledForAdd(indCol, dataObject);
                            //indCol.ID = Guid.NewGuid().ToString(); //向IndexColumn赋值主键id，前端生成
                            indCol.DataObjectID = dataObject.ID;
                            indCol.IndexID = ind.ID;
                            indCol.ColumnIndexType = 0;
                        });
                    }
                    if (ind.IncludeColumns != null)
                    {
                        ind.IncludeColumns.ForEach(incCol =>
                        {
                            EntityTools.FillSystemFiledForAdd(incCol, dataObject);
                            //incCol.ID = Guid.NewGuid().ToString(); //向IndexColumn赋值主键id，前端生成
                            incCol.DataObjectID = dataObject.ID;
                            incCol.IndexID = ind.ID;
                            incCol.ColumnIndexType = 1;
                        });
                        if (ind.Columns != null)
                        {
                            ind.Columns.AddRange(ind.IncludeColumns);
                        }
                    }
                });
            }
            //处理ColumnHelpSettings，给系统默认字段赋值
            if (dataObject.ColumnHelpSettings != null && dataObject.ColumnHelpSettings.Count > 0)
            {
                foreach (var setting in dataObject.ColumnHelpSettings)
                {
                    setting.ID = Guid.NewGuid().ToString(); 
                    setting.DataObjectID = dataObject.ID;
                    EntityTools.FillSystemFiledForAdd(setting, dataObject);
                };
            }
            //处理Index，给系统默认字段赋值
            if (dataObject.PresetData != null)
            {
                dataObject.PresetData.DataObjectID = dataObject.ID;
                EntityTools.FillSystemFiledForAdd(dataObject.PresetData, dataObject);
            }
            //处理Index，给系统默认字段赋值
            if (dataObject.ColumnCategoryInfos != null && dataObject.ColumnCategoryInfos.Count > 0)
            {
                foreach (var cateInfo in dataObject.ColumnCategoryInfos)
                {
                    //cateInfo.ID = Guid.NewGuid().ToString(); //前端赋值，因为同时可能给列信息已经绑定了该ID
                    cateInfo.DataObjectID = dataObject.ID;
                    EntityTools.FillSystemFiledForAdd(cateInfo, dataObject);
                };
            }
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    //新增DO
                    DataObjectDao.SaveDataObject(dataObject);
                    //新增DO.Column
                    DataColumnELBDao.CreateDataColumn(dataObject.Columns);
                    //新增DOR
                    _dataObjectRelationELBDao.CreateDataObjectRelation(dataObject.DataObjectRelations);
                    //新增预置数据
                    _staticDataObjectPresetDataELBDao.CreateStaticDataObjectPresetData(dataObject.PresetData);
                    //新增统一字段帮助
                    _dataObjectColumnHelpSettingELBDao.CreateColumnHelpSetting(dataObject.ColumnHelpSettings);
                    //新增字段分类信息
                    _dataColumnCategoryInfoELBDao.CreateDataColumnCategoryInfo(dataObject.ColumnCategoryInfos);
                    if (dataObject.DataObjectIndexs != null && dataObject.DataObjectIndexs.Count > 0)
                    {
                        //新增DO.Index
                        _dataObjectIndexELBDao.CreateDataObjectIndex(dataObject.DataObjectIndexs);
                        var dataObjectIndexColumns = dataObject.DataObjectIndexs.SelectMany(ind => ind.Columns)?.ToList();
                        //新增DO.IndexColumn
                        if (dataObjectIndexColumns != null && dataObjectIndexColumns.Count > 0)
                            _dataObjectIndexColumnELBDao.CreateDataObjectIndexColumn(dataObjectIndexColumns);
                    }
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.CreateError, $"{unifyCode}元数据保存失败", e);
            }
        }

        public virtual void SaveDataObjectIndexs(List<DataObjectIndex> dataObjectIndexs)
        {
            DataObjectDao.SaveDataObjectIndexs(dataObjectIndexs);
        }

        public virtual void SaveDataObjectIndexColumns(List<DataObjectIndexColumn> dataObjectIndexs)
        {
            DataObjectDao.SaveDataObjectIndexColumns(dataObjectIndexs);
        }
        #endregion

        #region 删除
        public virtual void DeleteDataObject(string dataObjectID)
        {
            var unifyCode = $"元数据类型{DataModelConst.DOMetaType}的元数据ID:{dataObjectID}";
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    DataObjectDao.DeleteDataObject(dataObjectID);
                    DataColumnELBDao.DeleteDataColumn(dataObjectID);
                    _dataObjectIndexELBDao.DeleteDataObjectIndex(dataObjectID);
                    _dataObjectRelationELBDao.DeleteDataObjectRelation(dataObjectID);
                    _staticDataObjectPresetDataELBDao.DeleteStaticDataObjectPresetData(dataObjectID);
                    _dataObjectColumnHelpSettingELBDao.DeleteColumnHelpSetting(dataObjectID);
                    _dataColumnCategoryInfoELBDao.DeleteDataColumnCategoryInfo(dataObjectID);
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.DeleteError, $"{unifyCode}元数据删除失败", e);
            }
        }

        #endregion
    }
}
